﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Media;
using AIStudio.Wpf.DiagramDesigner;
using AIStudio.Wpf.Mind.Helpers;

namespace AIStudio.Wpf.Mind.ViewModels
{
    public class MindDiagramViewModel : DiagramViewModel, IMindDiagramViewModel
    {
        #region
        private MindType _mindType = Mind.MindType.Mind;
        public MindType MindType
        {
            get
            {
                return _mindType;
            }
            set
            {
                if (SetProperty(ref _mindType, value))
                {
                    ExecutedChangeMindTypeCommand(value);
                }
            }
        }

        private MindThemeModel _mindThemeModel = MindThemeHelper.GetTheme("SkyBlue");
        public MindThemeModel MindThemeModel
        {
            get
            {
                return _mindThemeModel;
            }
            set
            {
                SetProperty(ref _mindThemeModel, value);
            }
        }
        public MindNode RootItem
        {
            get
            {
                return Items.OfType<MindNode>().FirstOrDefault();
            }
        }
        #endregion

        #region 命令
        private SimpleCommand _addParentCommand;
        public SimpleCommand AddParentCommand
        {
            get
            {
                return this._addParentCommand ?? (this._addParentCommand = new SimpleCommand(MindLevelEnable, ExecuteAddParentCommand));
            }
        }

        private SimpleCommand _addChildCommand;
        public SimpleCommand AddChildCommand
        {
            get
            {
                return this._addChildCommand ?? (this._addChildCommand = new SimpleCommand(MindExecuteEnable, this.ExecuteAddChildCommand));
            }
        }

        private SimpleCommand _AddPearCommand;
        public SimpleCommand AddPearCommand
        {
            get
            {
                return this._AddPearCommand ?? (this._AddPearCommand = new SimpleCommand(MindLevelEnable, this.ExecuteAddPearCommand));
            }
        }

        private SimpleCommand _moveForwardCommand;
        public SimpleCommand MoveForwardCommand
        {
            get
            {
                return this._moveForwardCommand ?? (this._moveForwardCommand = new SimpleCommand(MindExecuteEnable, ExecuteMoveForwardCommand));
            }
        }

        private SimpleCommand _moveBackCommand;
        public SimpleCommand MoveBackCommand
        {
            get
            {
                return this._moveBackCommand ?? (this._moveBackCommand = new SimpleCommand(MindExecuteEnable, ExecuteMoveBackCommand));
            }
        }

        private SimpleCommand _deleteCommand;
        public override SimpleCommand DeleteCommand
        {
            get
            {
                return this._deleteCommand ?? (this._deleteCommand = new SimpleCommand(MindLevelEnable, ExecuteDeleteCommand));
            }
        }

        private SimpleCommand _selectBrotherCommand;
        public SimpleCommand SelectBrotherCommand
        {
            get
            {
                return this._selectBrotherCommand ?? (this._selectBrotherCommand = new SimpleCommand(MindLevelEnable, ExecuteSelectBrotherCommand));
            }
        }

        private SimpleCommand _selectPearCommand;
        public SimpleCommand SelectPearCommand
        {
            get
            {
                return this._selectPearCommand ?? (this._selectPearCommand = new SimpleCommand(MindLevelEnable, ExecuteSelectPearCommand));
            }
        }

        private SimpleCommand _selectRouteCommand;
        public SimpleCommand SelectRouteCommand
        {
            get
            {
                return this._selectRouteCommand ?? (this._selectRouteCommand = new SimpleCommand(MindLevelEnable, ExecuteSelectRouteCommand));
            }
        }

        private SimpleCommand _selectChildCommand;
        public SimpleCommand SelectChildCommand
        {
            get
            {
                return this._selectChildCommand ?? (this._selectChildCommand = new SimpleCommand(MindLevelEnable, ExecuteSelectChildCommand));
            }
        }

        private SimpleCommand _addLinkCommand;
        public SimpleCommand AddLinkCommand
        {
            get
            {
                return this._addLinkCommand ?? (this._addLinkCommand = new SimpleCommand(MindExecuteEnable, ExecuteAddLinkCommand));
            }
        }

        private SimpleCommand _removeLinkCommand;
        public SimpleCommand RemoveLinkCommand
        {
            get
            {
                return this._removeLinkCommand ?? (this._removeLinkCommand = new SimpleCommand(MindExecuteEnable, ExecuteRemoveLinkCommand));
            }
        }

        private SimpleCommand _addImageCommand;
        public SimpleCommand AddImageCommand
        {
            get
            {
                return this._addImageCommand ?? (this._addImageCommand = new SimpleCommand(MindExecuteEnable, ExecuteAddImageCommand));
            }
        }

        private SimpleCommand _removeImageCommand;
        public SimpleCommand RemoveImageCommand
        {
            get
            {
                return this._removeImageCommand ?? (this._removeImageCommand = new SimpleCommand(MindExecuteEnable, ExecuteRemoveImageCommand));
            }
        }

        private SimpleCommand _addRemarkCommand;
        public SimpleCommand AddRemarkCommand
        {
            get
            {
                return this._addRemarkCommand ?? (this._addRemarkCommand = new SimpleCommand(MindExecuteEnable, ExecuteAddRemarkCommand));
            }
        }

        private SimpleCommand _removeRemarkCommand;
        public SimpleCommand RemoveRemarkCommand
        {
            get
            {
                return this._removeRemarkCommand ?? (this._removeRemarkCommand = new SimpleCommand(MindExecuteEnable, ExecuteRemoveRemarkCommand));
            }
        }

        private SimpleCommand _addPriorityCommand;
        public SimpleCommand AddPriorityCommand
        {
            get
            {
                return this._addPriorityCommand ?? (this._addPriorityCommand = new SimpleCommand(MindExecuteEnable, ExecuteAddPriorityCommand));
            }
        }

        private SimpleCommand _addRatioCommand;
        public SimpleCommand AddRatioCommand
        {
            get
            {
                return this._addRatioCommand ?? (this._addRatioCommand = new SimpleCommand(MindExecuteEnable, ExecuteAddRatioCommand));
            }
        }

        private SimpleCommand _addTagCommand;
        public SimpleCommand AddTagCommand
        {
            get
            {
                return this._addTagCommand ?? (this._addTagCommand = new SimpleCommand(MindExecuteEnable, ExecuteAddTagCommand));
            }
        }

        private SimpleCommand _removeTagCommand;
        public SimpleCommand RemoveTagCommand
        {
            get
            {
                return this._removeTagCommand ?? (this._removeTagCommand = new SimpleCommand(MindExecuteEnable, ExecuteRemoveTagCommand));
            }
        }

        private SimpleCommand _changeMindTypeCommand;
        public SimpleCommand ChangeMindTypeCommand
        {
            get
            {
                return this._changeMindTypeCommand ?? (this._changeMindTypeCommand = new SimpleCommand(ExecuteEnable, this.ExecutedChangeMindTypeCommand));
            }
        }

        private SimpleCommand _changeMindThemeCommand;
        public SimpleCommand ChangeMindThemeCommand
        {
            get
            {
                return this._changeMindThemeCommand ?? (this._changeMindThemeCommand = new SimpleCommand(ExecuteEnable, this.ExecutedChangeMindThemeCommand));
            }
        }

        private SimpleCommand _clearThemeCommand;
        public SimpleCommand ClearThemeCommand
        {
            get
            {
                return this._clearThemeCommand ?? (this._clearThemeCommand = new SimpleCommand(ExecuteEnable, this.ExecutedClearThemeCommand));
            }
        }

        private SimpleCommand _copyThemeCommand;
        public SimpleCommand CopyThemeCommand
        {
            get
            {
                return this._copyThemeCommand ?? (this._copyThemeCommand = new SimpleCommand(ExecuteEnable, this.ExecutedCopyThemeCommand));
            }
        }

        private SimpleCommand _pasteThemeCommand;
        public SimpleCommand PasteThemeCommand
        {
            get
            {
                return this._pasteThemeCommand ?? (this._pasteThemeCommand = new SimpleCommand(ExecuteEnable, this.ExecutedPasteThemeCommand));
            }
        }

        private SimpleCommand _expand2LevelCommand;
        public SimpleCommand Expand2LevelCommand
        {
            get
            {
                return this._expand2LevelCommand ?? (this._expand2LevelCommand = new SimpleCommand(ExecuteEnable, this.ExecutedExpand2LevelCommand));
            }
        }
        #endregion

        public MindDiagramViewModel()
        {

        }

        public override void Init()
        {
            if (Items.Count == 0)
            {
                InitRootItem();
            }
            GetChildren(RootItem);
            RootItem?.LayoutUpdated();
            base.Init();
        }

        public void InitRootItem()
        {
            MindNode level1node = new MindNode(this) { Root = this, Id = Guid.NewGuid(), Text = "思维导图" };
            level1node.InitLayout(true);
            Items.Add(level1node);
            level1node.IsSelected = true;

            CenterMoveCommand.Execute(level1node);
        }

        public bool MindExecuteEnable(object para)
        {
            if (ExecuteEnable(para) == false) return false;

            if (SelectedItem is MindNode) return true;

            return false;
        }

        private bool MindLevelEnable(object obj)
        {
            if (MindExecuteEnable(obj) == false) return false;

            return (SelectedItem as MindNode).NodeLevel != 0;
        }

        #region 操作
        public void ExecuteAddChildCommand(object parameter)
        {
            List<MindNode> items = new List<MindNode>();
            if (parameter is MindNode parent)
            {

            }
            else if (parameter is IEnumerable<MindNode> para)
            {
                parent = para.FirstOrDefault();//第一个固定为父节点
                items = para.Skip(1).ToList();
            }
            else
            {
                parent = SelectedItem as MindNode;
            }

            if (items?.Count == 0)
            {
                var node = new MindNode(this) { Text = "分支主题" };
                items.Add(node);
            }

            DoCommandManager.DoNewCommand(this.ToString(),
                () => {
                    foreach (var item in items)
                    {
                        parent.AddChild(item);
                    }
                    parent.LayoutUpdated();
                },
                () => {
                    foreach (var item in items)
                    {
                        parent.RemoveChild(item);
                    }
                    parent.LayoutUpdated();
                });

        }

        public void ExecuteAddParentCommand(object parameter)
        {
            List<MindNode> items = new List<MindNode>();
            if (parameter is MindNode node)
            {

            }
            else if (parameter is IEnumerable<MindNode> para)
            {
                node = para.FirstOrDefault();//第一个固定为父节点
                items = para.Skip(1).ToList();
            }
            else
            {
                node = SelectedItem as MindNode;
            }
            if (items?.Count == 0)
            {
                items.Add(new MindNode(this) { Text = "分支主题" });
            }

            if (node.Parent is MindNode parent)
            {
                DoCommandManager.DoNewCommand(this.ToString(),
                     () => {
                         int index = parent.Children.IndexOf(node);

                         parent.AddChild(items[0], index + 1);
                         parent.RemoveChild(node);
                         items[0].AddChild(node);

                         parent.LayoutUpdated();
                     },
                     () => {
                         int index = parent.Children.IndexOf(items[0]);
                         items[0].RemoveChild(node);
                         parent.AddChild(node, index + 1);

                         parent.LayoutUpdated();
                     });


            }
        }

        public void ExecuteAddPearCommand(object parameter)
        {
            List<MindNode> items = new List<MindNode>();
            if (parameter is MindNode pear)
            {

            }
            else if (parameter is IEnumerable<MindNode> para)
            {
                pear = para.FirstOrDefault();//第一个固定为同级节点
                items = para.Skip(1).ToList();
            }
            else
            {
                pear = SelectedItem as MindNode;
            }

            if (items?.Count == 0)
            {
                var node = new MindNode(this) { Text = "分支主题" };
                items.Add(node);
            }


            if (pear.Parent is MindNode parent)
            {
                DoCommandManager.DoNewCommand(this.ToString(),
                    () => {
                        int index = parent.Children.IndexOf(pear);
                        for (int i = 0; i < items.Count; i++)
                        {
                            parent.AddChild(items[i], index + i + 1);
                        }

                        parent.LayoutUpdated();
                    },
                    () => {
                        for (int i = 0; i < items.Count; i++)
                        {
                            parent.RemoveChild(items[i]);
                        }
                        parent.LayoutUpdated();
                    });

            }

        }

        private void ExecuteMoveBackCommand(object parameter)
        {
            if (parameter is MindNode node)
            {

            }
            else
            {
                node = SelectedItem as MindNode;
            }

            if (node.Parent is MindNode parent)
            {
                DoCommandManager.DoNewCommand(this.ToString(),
                    () => {
                        int index = parent.Children.IndexOf(node);
                        if (index < parent.Children.Count - 1)
                        {
                            parent.RemoveChild(node);
                            parent.AddChild(node, index + 1);
                            parent.LayoutUpdated();
                        }
                    },
                    () => {
                        int index = parent.Children.IndexOf(node);
                        if (index > 0)
                        {
                            parent.RemoveChild(node);
                            parent.AddChild(node, index - 1);
                            parent.LayoutUpdated();
                        }
                    });
            }

        }

        private void ExecuteMoveForwardCommand(object parameter)
        {
            if (parameter is MindNode node)
            {

            }
            else
            {
                node = SelectedItem as MindNode;
            }

            if (node.Parent is MindNode parent)
            {
                DoCommandManager.DoNewCommand(this.ToString(),
                  () => {
                      int index = parent.Children.IndexOf(node);
                      if (index > 0)
                      {
                          parent.RemoveChild(node);
                          parent.AddChild(node, index - 1);
                          parent.LayoutUpdated();
                      }
                  },
                  () => {
                      int index = parent.Children.IndexOf(node);
                      if (index < parent.Children.Count - 1)
                      {
                          parent.RemoveChild(node);
                          parent.AddChild(node, index + 1);
                          parent.LayoutUpdated();
                      }
                  });
            }

        }

        protected override bool Delete(object parameter)
        {
            List<MindNode> nodes = new List<MindNode>();
            if (parameter is MindNode node1)
            {
                nodes.Add(node1);
            }
            else if (parameter is IEnumerable<MindNode> para)
            {
                nodes.AddRange(para);
            }
            else
            {
                nodes.AddRange(SelectedItems.OfType<MindNode>());
            }

            if (nodes.FirstOrDefault()?.IsEditing != false)
            {
                return false;
            }

            nodes = nodes.Except(new List<MindNode> { RootItem }).ToList();

            if (nodes.Any())
            {
                Dictionary<MindNode, int> indexs = nodes.ToDictionary(p => p, p => p.ParentNode.Children.IndexOf(p));
                DoCommandManager.DoNewCommand(this.ToString(),
                  () => {
                      foreach (var node in nodes)
                      {
                          node.ParentNode.RemoveChild(node, true);
                      }
                      RootItem.LayoutUpdated();
                  },
                  () => {
                      foreach (var node in nodes)
                      {
                          node.ParentNode.AddChild(node, indexs[node]);
                      }
                      RootItem.LayoutUpdated();
                  });
                return true;
            }
            else
                return false;
        }

        protected override void ExecuteCenterMoveCommand(object parameter)
        {
            RootItem.Left = (PageSize.Width - RootItem.ItemWidth) / 2;
            RootItem.Top = (PageSize.Height - RootItem.ItemHeight) / 2;
            RootItem?.LayoutUpdated();
            FitViewModel = new FitViewModel() { BoundingRect = RootItem.GetBounds() };
        }

        private void ExecuteAddLinkCommand(object obj)
        {
            if (obj is object[] array && array.Length == 2)
            {
                SelectedItems.OfType<MindNode>().ToList().ForEach(p => 
                {
                    if (p.LinkInfo == null)
                        p.LinkInfo = new LinkInfo();

                    p.LinkInfo.Link = array[0]?.ToString();
                    p.LinkInfo.Text = array[1]?.ToString();
                  
               });
            }
        }

        private void ExecuteRemoveLinkCommand(object obj)
        {
            SelectedItems.OfType<MindNode>().ToList().ForEach(p => {
                if (p.LinkInfo != null)
                {
                    p.LinkInfo.Link = null; 
                    p.LinkInfo.Text = null;
                }
            });
        }

        private void ExecuteAddImageCommand(object obj)
        {
            if (obj is object[] array && array.Length == 2)
            {
                SelectedItems.OfType<MindNode>().ToList().ForEach(p => {
                    if (p.ImageInfo == null)
                        p.ImageInfo = new ImageInfo();

                    p.ImageInfo.Url = array[0]?.ToString();
                    p.ImageInfo.Text = array[1]?.ToString();

                });
            }
        }

        private void ExecuteRemoveImageCommand(object obj)
        {
            SelectedItems.OfType<MindNode>().ToList().ForEach(p => {
                if (p.ImageInfo != null)
                {
                    p.ImageInfo.Url = null;
                    p.ImageInfo.Text = null;
                }
            });
        }

        private void ExecuteAddRemarkCommand(object obj)
        {
            SelectedItems.OfType<MindNode>().ToList().ForEach(p => p.Remark = obj?.ToString());
        }

        private void ExecuteRemoveRemarkCommand(object obj)
        {
            SelectedItems.OfType<MindNode>().ToList().ForEach(p => p.Remark = null);
        }

        private void ExecuteAddPriorityCommand(object obj)
        {
            if (double.TryParse(obj.ToString(), out var priority))
            {
                SelectedItems.OfType<MindNode>().ToList().ForEach(p => p.Priority = priority);
            }
            else
            {
                SelectedItems.OfType<MindNode>().ToList().ForEach(p => p.Priority = null);
            }
        }

        private void ExecuteAddRatioCommand(object obj)
        {
            if (double.TryParse(obj.ToString(), out var rate))
            {
                SelectedItems.OfType<MindNode>().ToList().ForEach(p => p.Rate = rate);
            }
            else
            {
                SelectedItems.OfType<MindNode>().ToList().ForEach(p => p.Rate = null);
            }
        }

        private void ExecuteAddTagCommand(object obj)
        {
            SelectedItems.OfType<MindNode>().ToList().ForEach(p => {
                p.Tags.Add(obj?.ToString());
            });
        }

        private void ExecuteRemoveTagCommand(object obj)
        {
            SelectedItems.OfType<MindNode>().ToList().ForEach(p => {
                p.Tags.Remove(obj?.ToString());
            });
        }

        private void ExecutedChangeMindTypeCommand(object obj)
        {
            if (obj is MindType mindType)
            {
                Items.OfType<MindNode>().ToList().ForEach(item => { item.InitLayout(true); });
                Items.OfType<MindNode>().ToList().ForEach(item => { item.InitConnectLayout(); });
                RootItem?.LayoutUpdated();
            }
        }

        private void ExecutedChangeMindThemeCommand(object obj)
        {
            if (obj is string mindThemeModel)
            {
                MindThemeModel = MindThemeHelper.GetTheme(mindThemeModel);
                if (mindThemeModel.StartsWith("CoolLightYellow"))
                {
                    PageBackground = Colors.Black;
                }
                else
                {
                    PageBackground = Colors.White;
                }
                Items.OfType<MindNode>().ToList().ForEach(item => { item.ThemeChange(); });
                RootItem?.LayoutUpdated();
            }
        }

        private void ExecutedClearThemeCommand(object parameter)
        {
            List<MindNode> nodes = new List<MindNode>();
            if (parameter is MindNode node1)
            {
                nodes.Add(node1);
            }
            else if (parameter is IEnumerable<MindNode> para)
            {
                nodes.AddRange(para);
            }
            else
            {
                nodes.AddRange(SelectedItems.OfType<MindNode>());
            }

            if (nodes.Any())
            {
                DoCommandManager.DoNewCommand(this.ToString(),
                  () => {
                      foreach (var node in nodes)
                      {
                          node.ThemeChange();
                      }
                      RootItem.LayoutUpdated();
                  },
                  () => {
                      //ToDo
                  });
            }
        }

        private MindNode FormatNode;
        private void ExecutedCopyThemeCommand(object parameter)
        {
            if (parameter is MindNode node)
            {

            }
            else
            {
                node = SelectedItem as MindNode;
            }

            if (node != null)
            {
                FormatNode = node;
            }
        }

        private void ExecutedPasteThemeCommand(object parameter)
        {
            if (FormatNode != null)
            {
                List<MindNode> nodes = new List<MindNode>();
                if (parameter is MindNode node1)
                {
                    nodes.Add(node1);
                }
                else if (parameter is IEnumerable<MindNode> para)
                {
                    nodes.AddRange(para);
                }
                else
                {
                    nodes.AddRange(SelectedItems.OfType<MindNode>());
                }

                if (nodes.Any())
                {
                    DoCommandManager.DoNewCommand(this.ToString(),
                      () => {
                          foreach (var node in nodes)
                          {
                              CopyHelper.CopyPropertyValue(FormatNode.ColorViewModel, node.ColorViewModel);
                              CopyHelper.CopyPropertyValue(FormatNode.FontViewModel, node.FontViewModel);
                          }
                          RootItem.LayoutUpdated();
                      },
                      () => {
                          //ToDo
                      });
                }
             
            }

        }

        private void ExecutedExpand2LevelCommand(object obj)
        {
            int level = 0;
            int.TryParse(obj?.ToString(), out level);
            foreach (var item in Items.OfType<MindNode>())
            {
                if (item.NodeLevel == 0)
                {
                    continue;
                }
                else if (item.NodeLevel < level)
                {
                    item.IsExpanded = true;
                }
                else
                {
                    item.IsExpanded = false;
                }
            }
        }      
        #endregion
        protected override void ExecutedResetLayoutCommand(object obj)
        {
            foreach (var item in Items.OfType<MindNode>())
            {
                item.Offset = new DiagramDesigner.Geometrys.PointBase();
            }
            RootItem?.LayoutUpdated();
        }

        private void GetChildren(MindNode parent)
        {
            if (parent == null)
                return;

            parent.Children = new System.Collections.ObjectModel.ObservableCollection<MindNode>(Items.OfType<MindNode>().Where(p => p.ParentId == parent.Id));
            foreach (var item in Items.OfType<MindNode>().Where(p => p.ParentId == parent.Id))
            {
                item.Parent = parent;
                item.InitLayout(false);
                item.InitConnectLayout();
                GetChildren(item);
            }
        }

    }
}
